package pers.chao.cacheable.infrastructure.utils;

import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.core.*;
import org.springframework.util.CollectionUtils;
import pers.chao.cacheable.core.consts.CacheExpireUnit;
import pers.chao.tool.date.MillSeconds;
import pers.chao.tool.infrastructure.kv.Tuple;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * Description: Redis操作工具
 *
 * @author W.Chao
 * @date 2020/9/19 21:58
 **/
public final class RedisOp {
	private static RedisTemplate<String, Object> redisTemplateSelf;

	private static ValueOperations<String, Object> string;
	private static HashOperations<String, Object, Object> hash;
	private static SetOperations<String, Object> set;
	private static ListOperations<String, Object> list;
	private static ZSetOperations<String, Object> zset;

	private static final CacheExpireUnit DEFAULT_TIME_UNIT = CacheExpireUnit.MSEC;

	public RedisOp(RedisTemplate<String, Object> redisTemplate) {
		redisTemplateSelf = redisTemplate;
		string = redisTemplate.opsForValue();
		hash = redisTemplate.opsForHash();
		set = redisTemplate.opsForSet();
		list = redisTemplate.opsForList();
		zset = redisTemplate.opsForZSet();
	}

	// ==================> common <========================

	/**
	 * 指定缓存失效时间，下面的都依赖于此方法
	 *
	 * @param key
	 * @param expire
	 * @return
	 */
	public static boolean expire(String key, Long expire, CacheExpireUnit unit) {
		try {
			if (expire > 0) {
				// 根据单位把expire转换为毫秒数
				expire = MillSeconds.get(expire, unit.getUnit());
				redisTemplateSelf.expire(key, expire, TimeUnit.MILLISECONDS);
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 指定缓存失效时间，下面的都依赖于此方法
	 *
	 * @param key
	 * @param expire
	 * @return
	 */
	public static boolean expire(String key, Long expire) {
		try {
			if (expire > 0) {
				redisTemplateSelf.expire(key, expire, TimeUnit.MILLISECONDS);
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 获取过期时间
	 *
	 * @param key
	 * @return 返回0时代表永久有效
	 */
	public static Long getExpire(String key) {
		return redisTemplateSelf.getExpire(key, TimeUnit.MILLISECONDS);
	}

	/**
	 * 判断key是否存在
	 *
	 * @param key
	 * @return
	 */
	public static Boolean hasKey(String key) {
		try {
			return redisTemplateSelf.hasKey(key);
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 删除缓存，可多个
	 *
	 * @param keys
	 */
	@SuppressWarnings("unchecked")
	public static void del(String... keys) {
		if (keys != null && keys.length > 0) {
			if (keys.length == 1) {
				redisTemplateSelf.delete(keys[0]);
			} else {
				redisTemplateSelf.delete(CollectionUtils.arrayToList(keys));
			}
		}
	}

	// ==================> string <========================

	/**
	 * 普通缓存获取
	 *
	 * @param key
	 * @return
	 */
	public static Object get(String key) {
		return key == null ? null : string.get(key);
	}

	/**
	 * 普通缓存放入
	 *
	 * @param key
	 * @param value
	 * @return
	 */
	public static boolean set(String key, Object value) {
		try {
			string.set(key, value);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 普通缓存放入并设置失效时间
	 *
	 * @param key
	 * @param value
	 * @param expire
	 * @return
	 */
	public static boolean set(String key, Object value, Long expire, CacheExpireUnit unit) {
		try {
			string.set(key, value);
			if (expire > 0) {
				expire(key, expire, unit);
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 普通缓存放入并设置失效时间
	 *
	 * @param key
	 * @param value
	 * @param expire
	 * @return
	 */
	public static boolean set(String key, Object value, Long expire) {
		try {
			string.set(key, value);
			if (expire > 0) {
				expire(key, expire);
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 递增
	 *
	 * @param key
	 * @param delta
	 * @return
	 */
	public static Long incr(String key, long delta) {
		if (delta < 0) {
			throw new RuntimeException("递增因子应该大于0");
		}
		return string.increment(key, delta);
	}

	/**
	 * 递减
	 *
	 * @param key
	 * @param delta
	 * @return
	 */
	public static Long decr(String key, long delta) {
		if (delta < 0) {
			throw new RuntimeException("递减因子应该大于0");
		}
		return string.decrement(key, delta);
	}

	// ==================> hash <========================

	/**
	 * HashGet
	 *
	 * @param key
	 * @param item
	 * @return
	 */
	public static Object hget(String key, String item) {
		return hash.get(key, item);
	}

	/**
	 * 获取key所对应的的所有键值
	 *
	 * @param key
	 * @return
	 */
	public static Map<Object, Object> hmget(String key) {
		return hash.entries(key);
	}

	/**
	 * 向一个key中设置多个键值
	 *
	 * @param key
	 * @param map
	 * @return true成功 false失败
	 */
	public static Boolean hmset(String key, Map<String, Object> map) {
		try {
			hash.putAll(key, map);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 设置多个值，并设置失效时间
	 *
	 * @param key
	 * @param map
	 * @param expire
	 * @return true成功 false失败
	 */
	public static Boolean hmset(String key, Map<String, Object> map, Long expire, CacheExpireUnit unit) {
		try {
			hash.putAll(key, map);
			if (expire > 0) {
				expire(key, expire, unit);
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 设置多个值，并设置失效时间
	 *
	 * @param key
	 * @param map
	 * @param expire
	 * @return true成功 false失败
	 */
	public static Boolean hmset(String key, Map<String, Object> map, Long expire) {
		try {
			hash.putAll(key, map);
			if (expire > 0) {
				expire(key, expire);
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 向hash结构中放入数据，若item存在则会覆盖
	 *
	 * @param key
	 * @param item
	 * @param value
	 * @return
	 */
	public static Boolean hset(String key, String item, Object value) {
		try {
			hash.put(key, item, value);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 向hash结构中放入数据，若item存在则会覆盖,并设置失效时间
	 *
	 * @param key
	 * @param item
	 * @param value
	 * @param expire
	 * @return
	 */
	public static Boolean hset(String key, String item, Object value, Long expire, CacheExpireUnit unit) {
		try {
			hash.put(key, item, value);
			if (expire > 0) {
				expire(key, expire, unit);
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 向hash结构中放入数据，若item存在则会覆盖,并设置失效时间
	 *
	 * @param key
	 * @param item
	 * @param value
	 * @param expire
	 * @return
	 */
	public static Boolean hset(String key, String item, Object value, Long expire) {
		try {
			hash.put(key, item, value);
			if (expire > 0) {
				expire(key, expire);
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 删除hash结构中的键值
	 *
	 * @param key
	 * @param item
	 */
	public static void hdel(String key, Object... item) {
		hash.delete(key, item);
	}


	/**
	 * 判断某个键值是否在hash表中
	 *
	 * @param key
	 * @param item
	 * @return
	 */
	public static Boolean hHasKey(String key, String item) {
		return hash.hasKey(key, item);
	}

	/**
	 * hash减少，如果不存在，就会创建一个并把新增后的值返回
	 *
	 * @param key
	 * @param item
	 * @param by
	 * @return
	 */
	public static Long hincr(String key, String item, long by) {
		return hash.increment(key, item, by);
	}

	/**
	 * hash减少，如果不存在，就会创建一个并把新增后的值返回
	 *
	 * @param key
	 * @param item
	 * @param by
	 * @return
	 */
	public static Long hdecr(String key, String item, long by) {
		return hash.increment(key, item, -by);
	}

	// ==================> set <========================

	/**
	 * 根据key获取set中的所有值
	 *
	 * @param key
	 * @return
	 */
	public static Set<Object> sGet(String key) {
		try {
			return set.members(key);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 查询key的set中是否存在value
	 *
	 * @param key
	 * @param value
	 * @return
	 */
	public static Boolean sHasKey(String key, Object value) {
		try {
			return set.isMember(key, value);
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 将数据放入set中
	 *
	 * @param key
	 * @param values
	 * @return
	 */
	public static Long sSet(String key, Object... values) {
		try {
			return set.add(key, values);
		} catch (Exception e) {
			e.printStackTrace();
			return 0L;
		}
	}

	/**
	 * 将数据放入set中并设置失效时间
	 *
	 * @param key
	 * @param expire
	 * @param values
	 * @return
	 */
	public static Long sSet(String key, Long expire, Object... values) {
		try {
			Long count = set.add(key, values);
			if (expire > 0) {
				expire(key, expire);
			}
			return count;
		} catch (Exception e) {
			e.printStackTrace();
			return 0L;
		}
	}

	/**
	 * 将数据放入set中
	 *
	 * @param key
	 * @param c
	 * @return
	 */
	public static Long sSet(String key, Collection c) {
		try {
			for (Object o : c) {
				set.add(key, o);
			}
			return Long.valueOf(String.valueOf(c.size()));
		} catch (Exception e) {
			e.printStackTrace();
			return 0L;
		}
	}

	/**
	 * 将数据放入set中并设置失效时间
	 *
	 * @param key
	 * @param expire
	 * @param c
	 * @return
	 */
	public static Long sSet(String key, Long expire, Collection c) {
		try {
			for (Object o : c) {
				set.add(key, o);
			}
			if (expire > 0) {
				expire(key, expire);
			}
			return Long.valueOf(String.valueOf(c.size()));
		} catch (Exception e) {
			e.printStackTrace();
			return 0L;
		}
	}

	/**
	 * 将数据放入set中并设置失效时间
	 *
	 * @param key
	 * @param expire
	 * @param values
	 * @return
	 */
	public static Long sSet(String key, Long expire, CacheExpireUnit unit, Object... values) {
		try {
			Long count = set.add(key, values);
			if (expire > 0) {
				expire(key, expire, unit);
			}
			return count;
		} catch (Exception e) {
			e.printStackTrace();
			return 0L;
		}
	}

	/**
	 * 获取set的长度
	 *
	 * @param key
	 * @return
	 */
	public static Long sGetSize(String key) {
		try {
			return set.size(key);
		} catch (Exception e) {
			e.printStackTrace();
			return 0L;
		}
	}

	/**
	 * 移除set中的多个value值
	 *
	 * @param key
	 * @param values
	 * @return
	 */
	public static Long sRemove(String key, Object... values) {
		try {
			return set.remove(key, values);
		} catch (Exception e) {
			e.printStackTrace();
			return 0L;
		}
	}

	/**
	 * 移除set中的多个value值
	 *
	 * @param key
	 * @param c
	 * @return
	 */
	public static Long sRemove(String key, Collection c) {
		try {
			for (Object o : c) {
				set.remove(key, o);
			}
			return Long.valueOf(String.valueOf(c.size()));
		} catch (Exception e) {
			e.printStackTrace();
			return 0L;
		}
	}

	/**
	 * 删除key
	 *
	 * @param key
	 */
	public static void sDel(String key) {
		del(key);
	}

	// ==================> list <========================

	/**
	 * 获取list缓存内容
	 *
	 * @param key
	 * @param start
	 * @param end
	 * @return
	 */
	public static List<Object> lGet(String key, long start, long end) {
		try {
			return list.range(key, start, end);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 获取list缓存长度
	 *
	 * @param key
	 * @return
	 */
	public static Long lGetSize(String key) {
		try {
			return list.size(key);
		} catch (Exception e) {
			e.printStackTrace();
			return 0L;
		}
	}

	/**
	 * 通过索引获取list中的值
	 *
	 * @param key
	 * @param index 0->第一个元素，1->第二个元素，-1->最后一个元素，-2->倒数第二个元素
	 * @return
	 */
	public static Object lGetByIndex(String key, long index) {
		try {
			return list.index(key, index);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 将值从list的左边插入
	 *
	 * @param key
	 * @param value
	 * @return
	 */
	public static Boolean llPush(String key, Object value) {
		try {
			list.leftPush(key, value);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 将值从list的左边插入设置失效时间
	 *
	 * @param key
	 * @param expire
	 * @param unit
	 * @param value
	 * @return
	 */
	public static Boolean llPush(String key, Long expire, CacheExpireUnit unit, Object value) {
		try {
			list.leftPush(key, value);
			if (expire > 0) {
				expire(key, expire, unit);
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 将值从list的左边弹出
	 *
	 * @param key
	 * @return
	 */
	public static Object llPop(String key) {
		try {
			list.leftPop(key);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 将值从list的右边插入
	 *
	 * @param key
	 * @param value
	 * @return
	 */
	public static Boolean lrPush(String key, Object value) {
		try {
			list.rightPush(key, value);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 将值从list的右边插入设置失效时间
	 *
	 * @param key
	 * @param expire
	 * @param unit
	 * @param value
	 * @return
	 */
	public static Boolean lrPush(String key, Long expire, CacheExpireUnit unit, Object value) {
		try {
			list.rightPush(key, value);
			if (expire > 0) {
				expire(key, expire, unit);
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 将值从list的右边弹出
	 *
	 * @param key
	 * @return
	 */
	public static Object lrPop(String key) {
		try {
			list.rightPop(key);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 将多个数据从左边放入list
	 *
	 * @param key
	 * @param values
	 * @return
	 */
	public static Boolean llPushAll(String key, List<Object> values) {
		try {
			list.leftPushAll(key, values);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 将多个数据从左边放入list并设置失效时间
	 *
	 * @param key
	 * @param values
	 * @return
	 */
	public static Boolean llPushAll(String key, List<Object> values, Long expire, CacheExpireUnit unit) {
		try {
			list.leftPushAll(key, values);
			if (expire > 0) {
				expire(key, expire, unit);
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 将多个数据从右边放入list
	 *
	 * @param key
	 * @param values
	 * @return
	 */
	public static Boolean lrPushAll(String key, List<Object> values) {
		try {
			list.rightPushAll(key, values);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 将多个数据从右边放入list并设置失效时间
	 *
	 * @param key
	 * @param values
	 * @return
	 */
	public static Boolean lrPushAll(String key, List<Object> values, Long expire, CacheExpireUnit unit) {
		try {
			list.rightPushAll(key, values);
			if (expire > 0) {
				expire(key, expire, unit);
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 根据索引修改list中的值
	 *
	 * @param key
	 * @param index
	 * @param value
	 * @return
	 */
	public static Boolean lUpdateByIndex(String key, long index, Object value) {
		try {
			list.set(key, index, value);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 移除list中N个值为value的元素
	 *
	 * @param key
	 * @param count N
	 * @param value
	 * @return
	 */
	public static Long lRemove(String key, long count, Object value) {
		try {
			Long remove = list.remove(key, count, value);
			return remove;
		} catch (Exception e) {
			e.printStackTrace();
			return 0L;
		}
	}

	/**
	 * 元素裁剪
	 *
	 * @param key
	 * @param start
	 * @param stop
	 */
	public static void trim(String key, long start, long stop) {
		try {
			list.trim(key, start, stop);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// ==================> 有序set操作 <=====================

	/**
	 * 向有序集合key添加成员及对应的数值
	 *
	 * @param key
	 * @param value
	 * @param score
	 */
	public static Boolean zAdd(String key, String value, Double score) {
		return zset.add(key, value, score);
	}

	/**
	 * 向有序集合key添加成员及对应的数值并设置失效时间
	 *
	 * @param key
	 * @param value
	 * @param score
	 */
	public static Boolean zAdd(String key, String value, Double score, Long expire, CacheExpireUnit unit) {
		Boolean flag = zset.add(key, value, score);
		assert flag != null;
		if (flag && expire > 0) {
			expire(key, expire, unit);
		}
		return flag;
	}

	/**
	 * 向有序集合key添加多个成员及对应的数值
	 *
	 * @param key
	 * @param map
	 */
	public static Integer zAdd(String key, Map<String, Double> map) {
		for (Map.Entry<String, Double> entry : map.entrySet()) {
			zAdd(key, entry.getKey(), entry.getValue());
		}
		return map.size();
	}

	/**
	 * 向有序集合key添加多个成员及对应的数值并设置失效时间
	 *
	 * @param key
	 * @param map
	 */
	public static Integer zAdd(String key, Map<String, Double> map, Long expire, CacheExpireUnit unit) {
		for (Map.Entry<String, Double> entry : map.entrySet()) {
			zAdd(key, entry.getKey(), entry.getValue());
		}
		if (expire > 0) {
			expire(key, expire, unit);
		}
		return map.size();
	}

	/**
	 * 返回有序集key的个数
	 *
	 * @param key
	 */
	public static Long zSize(String key) {
		return zset.zCard(key);
	}

	/**
	 * 返回区间内的成员，
	 * 根据asc判断按照score从小到大还是从大到小排列
	 *
	 * @param key
	 * @param start
	 * @param end
	 * @param asc
	 */
	public static Set<Object> zRange(String key, Integer start, Integer end, Boolean asc) {
		return asc ? zset.range(key, start, end) : zset.reverseRange(key, start, end);
	}

	/**
	 * 返回score值在min~max之间的成员，
	 * limit!=null时，返回指定个数成员，
	 * limit大于已有数量时，返回全部成员，
	 * 排序规则如下：
	 * true：正序，从小到大
	 * false：逆序：从大到小
	 *
	 * @param key
	 * @param min
	 * @param max
	 * @param limit
	 * @param asc
	 * @return
	 */
	public static LinkedList<Tuple> zRangeByScoreWithScores(String key, Double min, Double max, Integer limit, Boolean asc) {
		Set<ZSetOperations.TypedTuple<Object>> typedTuples = null;
		if (asc) {
			typedTuples = zset.rangeByScoreWithScores(key, min, max);
		} else {
			typedTuples = zset.reverseRangeByScoreWithScores(key, min, max);
		}

		if (typedTuples != null) {
			LinkedList<Tuple> entryList = new LinkedList<>();

			if (limit != null && limit < typedTuples.size()) {
				for (ZSetOperations.TypedTuple<Object> next : typedTuples) {
					Tuple entry = new Tuple(next.getValue(), next.getScore());
					entryList.addLast(entry);
					limit--;
					if (limit == 0) {
						break;
					}
				}
			} else {
				for (ZSetOperations.TypedTuple<Object> next : typedTuples) {
					Tuple entry = new Tuple(next.getValue(), next.getScore());
					entryList.addLast(entry);
				}
			}
			return entryList;
		}
		return null;
	}


	/**
	 * 移除指定key中的多个成员
	 *
	 * @param key
	 * @param member
	 */
	public static Long zRemove(String key, Object... member) {
		return zset.remove(key, member);
	}

	/**
	 * 移除指定key中的多个成员
	 *
	 * @param key
	 * @param c
	 */
	public static Long zRemove(String key, Collection c) {
		for (Object o : c) {
			zset.remove(key, o);
		}
		return Long.valueOf(String.valueOf(c.size()));
	}

	/**
	 * 返回指定number的score值
	 *
	 * @param key
	 * @param member
	 * @return
	 */
	public static Double zScore(String key, String member) {
		return zset.score(key, member);
	}

	/**
	 * 递增
	 *
	 * @param key
	 * @param member
	 * @param delta
	 * @return
	 */
	public static Double zIncr(String key, String member, Double delta) {
		if (delta < 0) {
			throw new RuntimeException("递增因子应该大于0");
		}
		return zset.incrementScore(key, member, delta);
	}

	/**
	 * 递减
	 *
	 * @param key
	 * @param member
	 * @param delta
	 * @return
	 */
	public static Double zDecr(String key, String member, Double delta) {
		if (delta < 0) {
			throw new RuntimeException("递减因子应该大于0");
		}
		return zset.incrementScore(key, member, delta);
	}

	// ==================> 位图操作 <========================

	/**
	 * 将位图key中的pos位设置为0（false）或1（true）
	 *
	 * @param key
	 * @param pos
	 * @param status
	 * @return
	 */
	public static Boolean setBit(String key, Integer pos, Boolean status) {
		return redisTemplateSelf.execute((RedisCallback<Boolean>) con ->
				con.setBit(key.getBytes(), pos - 1, status)
		);
	}

	/**
	 * 将位图key中的pos位设置为0（false）或1（true）设置失效时间
	 *
	 * @param key
	 * @param pos
	 * @param status
	 * @return
	 */
	public static Boolean setBit(String key, Integer pos, Boolean status, Long expire, CacheExpireUnit unit) {
		Boolean flag = redisTemplateSelf.execute((RedisCallback<Boolean>) con ->
				con.setBit(key.getBytes(), pos - 1, status)
		);
		assert flag != null;
		if (expire > 0) {
			expire(key, expire, unit);
		}

		return flag;
	}

	/**
	 * 获得位图key中pos位的值为0或1
	 *
	 * @param key
	 * @param pos
	 * @return
	 */
	public static Boolean getBit(String key, Integer pos) {
		return redisTemplateSelf.execute((RedisCallback<Boolean>) con ->
				con.getBit(key.getBytes(), pos - 1)
		);
	}

	/**
	 * 统计某个位图键值中值为1的数量
	 *
	 * @param key
	 * @return
	 */
	public static Long bitCount(String key) {
		return redisTemplateSelf.execute((RedisCallback<Long>) con ->
				con.bitCount(key.getBytes())
		);
	}

	/**
	 * 统计某个位图键值中值为1的数量，范围限制在[start,end]
	 *
	 * @param key
	 * @param start
	 * @param end
	 * @return
	 */
	public static Long bitCount(String key, long start, long end) {
		return redisTemplateSelf.execute((RedisCallback<Long>) con ->
				con.bitCount(key.getBytes(), start - 1, end - 1)
		);
	}

	/**
	 * Bit OP 操作
	 *
	 * @param op
	 * @param saveKey
	 * @param desKey
	 * @return
	 */
	public static Long bitOp(RedisStringCommands.BitOperation op, String saveKey, String... desKey) {
		byte[][] bytes = new byte[desKey.length][];
		for (int i = 0; i < desKey.length; i++) {
			bytes[i] = desKey[i].getBytes();
		}
		return redisTemplateSelf.execute((RedisCallback<Long>) con ->
				con.bitOp(op, saveKey.getBytes(), bytes)
		);
	}

	/**
	 * Bit删除
	 *
	 * @param key
	 */
	public static void bitDel(String key) {
		redisTemplateSelf.execute((RedisCallback<Long>) con ->
				con.del(key.getBytes())
		);
	}
}
